﻿#region License
// Copyright (c) Dmitry Antonenko (http://hystrix.com.ua)
// 
// Licensed under the Apache License, Version 2.0 (the "License"); 
// you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at 
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software 
// distributed under the License is distributed on an "AS IS" BASIS, 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
// See the License for the specific language governing permissions and 
// limitations under the License.
// 
// The latest version of this file can be found at http://fluentfilters.codeplex.com/
#endregion

namespace FluentFilters
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;

    public class FilterRegistry: IFilterRegistry 
    {
        #region Fields

        private readonly List<FilterRecord> _registry;

        #endregion

        #region Constructor

        public FilterRegistry()
        {
            _registry = new List<FilterRecord>();
        }

        #endregion

        #region Implementation of IFilterRegistry
        
        /// <summary>
        /// Clear all registered filters
        /// </summary>
        public void Clear()
        {
            _registry.Clear();
        }

        /// <summary>
        /// Add action filter that will be used for all application
        /// </summary>
        /// <typeparam name="T">Filter type</typeparam>
        public void Add<T>()
        {
            _registry.Add(new FilterRecord(Enumerable.Empty<FilterCriteriaResult>(), typeof(T)));
        }

        /// <summary>
        /// Add action filter and specify criteria
        /// </summary>
        /// <typeparam name="T">Filter type</typeparam>
        /// <param name="criteria">The criteria</param>
        public void Add<T>(Action<IFilterCriteriaBuilder> criteria)
        {
            var builder = new FilterCriteriaBuilder();
            criteria(builder);
            
            _registry.Add(new FilterRecord(builder.GetResults(), typeof(T)));
        }

        /// <summary>
        /// Remove the action filter by specified type
        /// </summary>
        /// <typeparam name="T">Filter type</typeparam>
        public void Remove<T>()
        {
            _registry.RemoveAll(f => f.FilterType.Equals(typeof(T)));
        }

        /// <summary>
        /// Gets registered filters
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public FilterInfo GetFilters(FilterRegistryContext context)
        {
            var filters = new FilterInfo();

            foreach (var record in _registry)
            {
                if (record.Match(context))
                {
                    object filterObject = GetFilterInstance(record.FilterType);

                    if (filterObject is IActionFilter)
                        filters.ActionFilters.Add((IActionFilter)filterObject);

                    if (filterObject is IAuthorizationFilter)
                        filters.AuthorizationFilters.Add((IAuthorizationFilter)filterObject);

                    if (filterObject is IExceptionFilter)
                        filters.ExceptionFilters.Add((IExceptionFilter)filterObject);

                    if (filterObject is IResultFilter)
                        filters.ResultFilters.Add((IResultFilter)filterObject);
                }
            }

            return filters;
        }

        /// <summary>
        /// Get registered filter instance by type
        /// </summary>
        /// <param name="filterType">Type of the filter</param>
        /// <returns></returns>
        public virtual object GetFilterInstance(Type filterType)
        {
            return Activator.CreateInstance(filterType);
        }

        #endregion
    }
}


